/*
 * This file contains classes and functions for the editor backends.
 */

// Load template to html element
function loadHtmlTemplateToElement(url, htmlElement, completionHandler) {

    var txtFile = new XMLHttpRequest();
    txtFile.open("GET", url, true);
    txtFile.onreadystatechange = function() {
        if (txtFile.readyState === 4) {  // Makes sure the document is ready to parse.
            if (txtFile.status === 200) {  // Makes sure it's found the file.
                htmlElement.innerHTML = txtFile.responseText;
                if (completionHandler)
                    completionHandler.evLoadFinished();
            }
        }
    };
    txtFile.send(null);
}

// Load availlable types to html select
function loadTypesTo(html) {
    var primArr = [PrimitiveType.integer, PrimitiveType.boolean, PrimitiveType.real, PrimitiveType.string, PrimitiveType.void];
    html.innerHTML = "";
    html.innerHTML += "<optgroup label=\"Built-in types\">";
    for (var i = 0; i < primArr.length; i++) {
        var prim = primArr[i];
        html.innerHTML += "<option value=\"" + prim.uid + "\">" + prim.name + "</option>";
    }
    html.innerHTML += "</optgroup><optgroup label=\"User types\">";
    var arr = project.model.modelElements;
    arr.sort();
    for (var i = 0; i < arr.length; i++) {
        var e = arr[i];
        if (e instanceof Class) {
            html.innerHTML += "<option value=\"" + e.uid + "\">" + ((e.name)?e.name:"(unnamed)") + "</option>";
        }
    }
    html.innerHTML += "</optgroup>";

}

// Load stereotype list to html element
function loadStereotypeEntries(html, stereotypesArr) {
    html.innerHTML = "";
    if (stereotypesArr.length === 0) {
        html.innerHTML += "<tr><td class=\"editor_list_empty\"></td></tr>";
        return;
    }
    for (var i = 0; i < stereotypesArr.length; i++) {
        var st = stereotypesArr[i];
        html.innerHTML +=
                "<tr><td class=\"editor_list_name\">" +
                ((st.name)?(st.name):"(unnamed)") +
                "</td><td class=\"editor_list_edit\">" +
                "<img src=\"media/icons/icon_edit_16px.png\" class=\"editor_list_edit_button\" " +
                "  onclick=\"project.currentEditor.evSwitchToStereotypeEditor(" + st.uid + ")\"/>" +
                "</td><td class=\"editor_list_delete\">" +
                "<img src=\"media/icons/icon_delete_16px.png\" class=\"editor_list_delete_button\" " +
                "  onclick=\"project.currentEditor.evDeleteStereotype(" + st.uid + ")\"/>" +
                "</td></tr>";
    }
}

// Load attribute list to html element
function loadAttributeEntries(html, attributesArr) {
    html.innerHTML = "";
    if (attributesArr.length === 0) {
        html.innerHTML += "<tr><td class=\"editor_list_empty\"></td></tr>";
        return;
    }
    for (var i = 0; i < attributesArr.length; i++) {
        var attr = attributesArr[i];
        html.innerHTML +=
                "<tr><td class=\"editor_list_name\">" +
                ((attr.name)?(attr.name):"(unnamed)") +
                "</td><td class=\"editor_list_edit\">" +
                "<img src=\"media/icons/icon_edit_16px.png\" class=\"editor_list_edit_button\" " +
                "  onclick=\"project.currentEditor.evSwitchToAttributeEditor(" + attr.uid + ")\"/>" +
                "</td><td class=\"editor_list_delete\">" +
                "<img src=\"media/icons/icon_delete_16px.png\" class=\"editor_list_delete_button\" " +
                "  onclick=\"project.currentEditor.evDeleteAttribute(" + attr.uid + ")\"/>" +
                "</td></tr>";
    }
}

// Load operation list to html element
function loadOperationEntries(html, operationArr) {
    html.innerHTML = "";
    if (operationArr.length === 0) {
        html.innerHTML += "<tr><td class=\"editor_list_empty\"></td></tr>";
        return;
    }
    for (var i = 0; i < operationArr.length; i++) {
        var op = operationArr[i];
        html.innerHTML +=
                "<tr><td class=\"editor_list_name\">" +
                ((op.name)?(op.name):"(unnamed)") +
                "</td><td class=\"editor_list_edit\">" +
                "<img src=\"media/icons/icon_edit_16px.png\" class=\"editor_list_edit_button\" " +
                "  onclick=\"project.currentEditor.evSwitchToOperationEditor(" + op.uid + ")\"/>" +
                "</td><td class=\"editor_list_delete\">" +
                "<img src=\"media/icons/icon_delete_16px.png\" class=\"editor_list_delete_button\" " +
                "  onclick=\"project.currentEditor.evDeleteOperation(" + op.uid + ")\"/>" +
                "</td></tr>";
    }
}

// Load parameter list to html element
function loadParameterEntries(html, parameterArr) {
    html.innerHTML = "";
    if (parameterArr.length === 0) {
        html.innerHTML += "<tr><td class=\"editor_list_empty\"></td></tr>";
        return;
    }
    for (var i = 0; i < parameterArr.length; i++) {
        var par = parameterArr[i];
        html.innerHTML +=
                "<tr><td class=\"editor_list_name\">" +
                ((par.name)?(par.name):"(unnamed)") +
                "</td><td class=\"editor_list_edit\">" +
                "<img src=\"media/icons/icon_edit_16px.png\" class=\"editor_list_edit_button\" " +
                "  onclick=\"project.currentEditor.evSwitchToParameterEditor(" + par.uid + ")\"/>" +
                "</td><td class=\"editor_list_delete\">" +
                "<img src=\"media/icons/icon_delete_16px.png\" class=\"editor_list_delete_button\" " +
                "  onclick=\"project.currentEditor.evDeleteParameter(" + par.uid + ")\"/>" +
                "</td></tr>";
    }
}

// ======================== ELEMENT EDITOR ========================
// 
// Base class for editors
function ElementEditor(modelElement, parentEditor) {
    this.htmlEditorDiv = null;
    this.htmlEditorHeader = null;
    this.modelElement = (modelElement !== undefined) ? modelElement : null;
    this.parentEditor = (parentEditor !== undefined) ? parentEditor : null;
}
// Event callback to call when a property has been changed through the 
// editor UI elements.
ElementEditor.prototype.evPropertyChanged = function(propName, propValue) {
    throw "ElementEditor.evPropertyChanged unimplemented";
};
//
ElementEditor.prototype.fillData = function() {
    throw "ElementEditor.fillData unimplemented";
};
// 
ElementEditor.prototype.evLoadFinished = function() {
    this.fillData();
};
//
ElementEditor.prototype.deleteData = function() {
    if (this.htmlEditorDiv) {
        this.htmlEditorDiv.innerHTML = "";
    }
};
ElementEditor.prototype.evBackToParent = function() {
    project.setEditor(this.parentEditor);
};

ElementEditor.prototype.evNewStereotype = function() {
    project.evCreateNewStereotype(this);
};
ElementEditor.prototype.evDeleteStereotype = function(stereotypeUid) {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    var st = this.modelElement.getStereotypeById(stereotypeUid);
    if (st !== null) {
        this.modelElement.removeStereotype(st);
        project.model.removeAndDestroyElement(st);
//        project.setEditor(this);
        this.fillStereotypes();
    }
};
ElementEditor.prototype.evSwitchToStereotypeEditor = function(stereotypeUid) {
    var st = this.modelElement.getStereotypeById(stereotypeUid);
    if (st !== null) {
        project.setEditor(new StereotypeEditor(st, this));
    }
};
// Remove element from the current diagram
ElementEditor.prototype.evDeleteDiagramElement = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    if (project.currentDiagram) {
        var e = project.currentDiagram.getElementByModelId(this.modelElement.uid);
        project.currentDiagram.removeElement(e);
        project.setEditor(this.parentEditor);
    }
};




// ======================== CLASS/INTERFACE EDITOR ========================
// 
ClassInterfaceEditor.prototype = new ElementEditor;
function ClassInterfaceEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlVisibilityInput = null;
    this.htmlIsAbstractInput = null;
    this.htmlAttributeListInput = null;
    this.htmlOperationListInput = null;
}
ClassInterfaceEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    if (this.modelElement.isInterface) {
        loadHtmlTemplateToElement("templates/template_interface.html", this.htmlEditorDiv, this);
    } else {
        loadHtmlTemplateToElement("templates/template_class.html", this.htmlEditorDiv, this);
    }

};
ClassInterfaceEditor.prototype.fillData = function() {

    // get references to elements
    if (this.modelElement.isInterface) {

        this.htmlNameInput = document.getElementById("InterfaceAttributeName");
        this.htmlVisibilityInput = document.getElementById("InterfaceAttributeVisitility");

        this.htmlNameInput.value = this.modelElement.name;
        this.htmlVisibilityInput.value = this.modelElement.visibility;

        this.fillOperations();
        this.fillStereotypes();

    } else {

        this.htmlNameInput = document.getElementById("ClassAttributeName");
        this.htmlVisibilityInput = document.getElementById("ClassAttributeVisitility");
        this.htmlIsAbstractInput = document.getElementById("ClassAttributeIsAbstract");

        this.htmlNameInput.value = this.modelElement.name;
        this.htmlVisibilityInput.value = this.modelElement.visibility;
        this.htmlIsAbstractInput.checked = this.modelElement.isAbstract;

        this.fillAttributes();
        this.fillOperations();
        this.fillStereotypes();
    }
};

ClassInterfaceEditor.prototype.fillAttributes = function() {
    this.htmlAttributeListInput = document.getElementById("ClassAttributeAttributeList");
    loadAttributeEntries(this.htmlAttributeListInput, this.modelElement.attributes);
};

ClassInterfaceEditor.prototype.fillOperations = function() {

    this.htmlOperationListInput = document.getElementById(this.modelElement.isInterface ? "InterfaceAttributeOperationList" : "ClassAttributeOperationList");
    loadOperationEntries(this.htmlOperationListInput, this.modelElement.operations);
};

ClassInterfaceEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById(this.modelElement.isInterface ? "InterfaceAttributeStereotypeList" : "ClassAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};

// Event callback to call when a property has been changed through the 
// editor UI elements.
ClassInterfaceEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;
        case "visibility":
            this.modelElement.setVisibility(propValue);
            break;
        case "isAbstract":
            this.modelElement.setIsAbstract(propValue);
            break;
    }
};
ClassInterfaceEditor.prototype.evNewAttribute = function() {
    project.evCreateNewAttribute(this);
};
ClassInterfaceEditor.prototype.evNewOperation = function() {
    project.evCreateNewOperation(this);
};
ClassInterfaceEditor.prototype.evSwitchToAttributeEditor = function(attributeUid) {
    var attr = this.modelElement.getAttributeById(attributeUid);
    if (attr !== null) {
        var attrEditor = new AttributeEditor(attr, this);
        project.setEditor(attrEditor);
    }
};
ClassInterfaceEditor.prototype.evSwitchToOperationEditor = function(operationUid) {
    var op = this.modelElement.getOperationById(operationUid);
    if (op !== null) {
        var opEditor = new OperationEditor(op, this);
        project.setEditor(opEditor);
    }
};
ClassInterfaceEditor.prototype.evDeleteAttribute = function(attributeUid) {
    
    var c = confirm("This will delete the attribute PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    var attr = this.modelElement.getAttributeById(attributeUid);
    if (attr !== null) {
        this.modelElement.removeAttribute(attr);
        project.model.removeAndDestroyElement(attr);
//        project.setEditor(this);
        this.fillAttributes();
    }
};
ClassInterfaceEditor.prototype.evDeleteOperation = function(operationUid) {
    
    var c = confirm("This will delete the operation PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    var op = this.modelElement.getOperationById(operationUid);
    if (op !== null) {
        this.modelElement.removeOperation(op);
        project.model.removeAndDestroyElement(op);
//        project.setEditor(this);
        this.fillOperations();
    }
};
ClassInterfaceEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    project.model.removeAndDestroyElement(this.modelElement);
    project.setEditor(this.parentEditor);
};


// ======================== ATTRIBUTE EDITOR ========================
// 
AttributeEditor.prototype = new ElementEditor;
function AttributeEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlVisibilityInput = null;
    this.htmlMultiplicityInput = null;
    this.htmlIsClassifierInput = null;
    this.htmlTypeInput = null;
    this.htmlDefaultValueInput = null;
}
AttributeEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("AttributeAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};
AttributeEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_attribute.html", this.htmlEditorDiv, this);

};
AttributeEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("AttributeAttributeName");
    this.htmlVisibilityInput = document.getElementById("AttributeAttributeVisibility");
    this.htmlMultiplicityInput = document.getElementById("AttributeAttributeMultiplicity");
    this.htmlIsClassifierInput = document.getElementById("AttributeAttributeOwnership");
    this.htmlTypeInput = document.getElementById("AttributeAttributeType");
    this.htmlDefaultValueInput = document.getElementById("AttributeAttributeDefaultValue");

    loadTypesTo(this.htmlTypeInput);

    this.htmlNameInput.value = this.modelElement.name;
    this.htmlVisibilityInput.value = this.modelElement.visibility;
    this.htmlMultiplicityInput.value = this.modelElement.multiplicity;
    this.htmlIsClassifierInput.checked = this.modelElement.isClassifierScope;
    this.htmlTypeInput.value = (this.modelElement.type !== null) ? this.modelElement.type.uid : null;
    this.htmlDefaultValueInput.value = this.modelElement.defaultValue;

    this.fillStereotypes();
};

// Event callback to call when a property has been changed through the 
// editor UI elements.
AttributeEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;
        case "visibility":
            this.modelElement.setVisibility(propValue);
            break;
        case "multiplicity":
            this.modelElement.setMultiplicity(propValue);
            break;
        case "isClassifier":
            this.modelElement.setIsClassifierScope(propValue);
            break;
        case "type":
            var type = null;
            if (propValue == PrimitiveType.integer.uid) {
                type = PrimitiveType.integer
            } else if (propValue == PrimitiveType.boolean.uid) {
                type = PrimitiveType.boolean;
            } else if (propValue == PrimitiveType.real.uid) {
                type = PrimitiveType.real;
            } else if (propValue == PrimitiveType.string.uid) {
                type = PrimitiveType.string;
            } else if (propValue == PrimitiveType.void.uid) {
                type = PrimitiveType.void;
            } else {
                type = project.model.getElementById(propValue);
            }
            this.modelElement.setType(type);
            break;
        case "defaultValue":
            this.modelElement.setDefaultValue(propValue);
            break;
    }
};
AttributeEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    if(this.parentEditor) {
        this.parentEditor.modelElement.removeAttribute(this.modelElement);
        this.modelElement.destroy();
        project.setEditor(this.parentEditor);
    }else{
        // TODO ERROR
    }
};


// ======================== OPERATION EDITOR ========================
// 
OperationEditor.prototype = new ElementEditor;
function OperationEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlVisibilityInput = null;
    this.htmlIsClassifierInput = null;
    this.htmlIsAstractInput = null;
    this.htmlReturnTypeInput = null;
    this.htmlParameterListInput = null;
}
OperationEditor.prototype.fillParameters = function() {
    this.htmlParameterListInput = document.getElementById("OperationAttributeParameterList");
    loadParameterEntries(this.htmlParameterListInput, this.modelElement.parameters);
};
OperationEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("OperationAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};

OperationEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_operation.html", this.htmlEditorDiv, this);

};
OperationEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("OperationAttributeName");
    this.htmlVisibilityInput = document.getElementById("OperationAttributeVisitility");
    this.htmlIsClassifierInput = document.getElementById("OperationAttributeOwnership");
    this.htmlIsAstractInput = document.getElementById("OperationAttributeIsAbstract");
    this.htmlReturnTypeInput = document.getElementById("OperationAttributeReturnType");

    loadTypesTo(this.htmlReturnTypeInput);

    this.htmlNameInput.value = this.modelElement.name;
    this.htmlVisibilityInput.value = this.modelElement.visibility;
    this.htmlIsClassifierInput.checked = this.modelElement.isClassifierScope;
    this.htmlIsAstractInput.checked = this.modelElement.isAbstract;
    this.htmlReturnTypeInput.value = (this.modelElement.returnType !== null) ? this.modelElement.returnType.uid : null;

    this.fillParameters();
    this.fillStereotypes();

};
// Event callback to call when a property has been changed through the 
// editor UI elements.
OperationEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;
        case "visibility":
            this.modelElement.setVisibility(propValue);
            break;
        case "isClassifier":
            this.modelElement.setIsClassifierScope(propValue);
            break;
        case "isAbstract":
            this.modelElement.setIsAbstract(propValue);
            break;
        case "returnType":
            var type = null;
            if (propValue == PrimitiveType.integer.uid) {
                type = PrimitiveType.integer
            } else if (propValue == PrimitiveType.boolean.uid) {
                type = PrimitiveType.boolean;
            } else if (propValue == PrimitiveType.real.uid) {
                type = PrimitiveType.real;
            } else if (propValue == PrimitiveType.string.uid) {
                type = PrimitiveType.string;
            } else if (propValue == PrimitiveType.void.uid) {
                type = PrimitiveType.void;
            } else {
                type = project.model.getElementById(propValue);
            }
            this.modelElement.setReturnType(type);
            break;
    }
};
OperationEditor.prototype.evNewParameter = function() {
    project.evCreateNewParameter(this);
};
OperationEditor.prototype.evSwitchToParameterEditor = function(parameterUid) {
    var par = this.modelElement.getParameterById(parameterUid);
    if (par !== null) {
        var parEditor = new ParameterEditor(par, this);
        project.setEditor(parEditor);
    }
};
OperationEditor.prototype.evDeleteParameter = function(parameterUid) {
    
    var c = confirm("This will delete the parameter PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    var par = this.modelElement.getParameterById(parameterUid);
    if (par !== null) {
        this.modelElement.removeParameter(par);
        project.model.removeAndDestroyElement(par);
//        project.setEditor(this);
        this.fillParameters();
    }
};
OperationEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    if(this.parentEditor) {
        this.parentEditor.modelElement.removeOperation(this.modelElement);
        this.modelElement.destroy();
        project.setEditor(this.parentEditor);
    }else{
        // TODO ERROR
    }
};

// ======================== PARAMETER EDITOR ========================
// 
ParameterEditor.prototype = new ElementEditor;
function ParameterEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlTypeInput = null;
    this.htmlDefaultValueInput = null;
}
ParameterEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("ParameterAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};
ParameterEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_operation_parameter.html", this.htmlEditorDiv, this);

};
ParameterEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("ParameterAttributeName");
    this.htmlTypeInput = document.getElementById("ParameterAttributeType");
    this.htmlDefaultValueInput = document.getElementById("ParameterAttributeDefaultValue");

    loadTypesTo(this.htmlTypeInput);

    this.htmlNameInput.value = this.modelElement.name;
    this.htmlTypeInput.value = (this.modelElement.type !== null) ? this.modelElement.type.uid : null;
    this.htmlDefaultValueInput.value = this.modelElement.defaultValue;

    this.fillStereotypes();
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
ParameterEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;
        case "defaultValue":
            this.modelElement.setDefaultValue(propValue);
            break;
        case "type":
            var type = null;
            if (propValue == PrimitiveType.integer.uid) {
                type = PrimitiveType.integer
            } else if (propValue == PrimitiveType.boolean.uid) {
                type = PrimitiveType.boolean;
            } else if (propValue == PrimitiveType.real.uid) {
                type = PrimitiveType.real;
            } else if (propValue == PrimitiveType.string.uid) {
                type = PrimitiveType.string;
            } else if (propValue == PrimitiveType.void.uid) {
                type = PrimitiveType.void;
            } else {
                type = project.model.getElementById(propValue);
            }
            this.modelElement.setType(type);
            break;
    }
};
ParameterEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    if(this.parentEditor) {
        this.parentEditor.modelElement.removeParameter(this.modelElement);
        this.modelElement.destroy();
        project.setEditor(this.parentEditor);
    }else{
        // TODO ERROR
    }
};

// ======================== ASSOCIATION EDITOR ========================
// 
AssociationEditor.prototype = new ElementEditor;
function AssociationEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlTypeInput = null;

    this.htmlSourceEndInput = null;
    this.htmlTargetEndInput = null;

    this.htmlSourceEndNameInput = null;
    this.htmlSourceEndVisibilityInput = null;
    this.htmlSourceEndMultiplicityInput = null;
    this.htmlSourceEndIsNavigableInput = null;
    this.htmlTargetEndNameInput = null;
    this.htmlTargetEndVisibilityInput = null;
    this.htmlTargetEndMultiplicityInput = null;
    this.htmlTargetEndIsNavigableInput = null;
}
AssociationEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("AssociationAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};
AssociationEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_association.html", this.htmlEditorDiv, this);
};
AssociationEditor.prototype.fillData = function() {

    this.htmlEditorHeader = document.getElementById("AssociationEditorHeader");

    this.htmlNameInput = document.getElementById("AssociationAttributeName");
    this.htmlTypeInput = document.getElementById("AssociationAttributeType");

    this.htmlSourceEndInput = document.getElementById("AssociationAttributeSource");
    this.htmlTargetEndInput = document.getElementById("AssociationAttributeTarget");

    this.htmlSourceEndNameInput = document.getElementById("AssociationSourceEndAttributeName");
    this.htmlSourceEndVisibilityInput = document.getElementById("AssociationSourceEndAttributeVisibility");
    this.htmlSourceEndMultiplicityInput = document.getElementById("AssociationSourceEndAttributeMultiplicity");
    this.htmlSourceEndIsNavigableInput = document.getElementById("AssociationSourceEndAttributeIsNavigable");
    this.htmlTargetEndNameInput = document.getElementById("AssociationTargetEndAttributeName");
    this.htmlTargetEndVisibilityInput = document.getElementById("AssociationTargetEndAttributeVisibility");
    this.htmlTargetEndMultiplicityInput = document.getElementById("AssociationTargetEndAttributeMultiplicity");
    this.htmlTargetEndIsNavigableInput = document.getElementById("AssociationTargetEndAttributeIsNavigable");

    this.htmlNameInput.value = this.modelElement.name;
    if (this.modelElement.isAssociation) {
        this.htmlTypeInput.value = "association";
        this.htmlEditorHeader.innerHTML = "Association";
    }
    if (this.modelElement.isAggregation) {
        this.htmlTypeInput.value = "aggregation";
        this.htmlEditorHeader.innerHTML = "Aggregation";
    }
    if (this.modelElement.isComposition) {
        this.htmlTypeInput.value = "composition";
        this.htmlEditorHeader.innerHTML = "Composition";
    }

    this.htmlSourceEndInput.value = this.modelElement.sourceEnd.name;
    this.htmlTargetEndInput.value = this.modelElement.targetEnd.name;

    this.htmlSourceEndNameInput.value = this.modelElement.sourceEndInfo.name;
    this.htmlSourceEndVisibilityInput.value = this.modelElement.sourceEndInfo.visibility;
    this.htmlSourceEndMultiplicityInput.value = this.modelElement.sourceEndInfo.multiplicity;
    this.htmlSourceEndIsNavigableInput.value = this.modelElement.sourceEndInfo.isNavigable;
    this.htmlTargetEndNameInput.value = this.modelElement.targetEndInfo.name;
    this.htmlTargetEndVisibilityInput.value = this.modelElement.targetEndInfo.visibility;
    this.htmlTargetEndMultiplicityInput.value = this.modelElement.targetEndInfo.multiplicity;
    this.htmlTargetEndIsNavigableInput.value = this.modelElement.targetEndInfo.isNavigable;

    this.fillStereotypes();
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
AssociationEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;
        case "type":
            switch (propValue) {
                case "association":
                    this.modelElement.setIsAssociation(true);
                    this.modelElement.setIsAggregation(false);
                    this.modelElement.setIsComposition(false);
                    break;
                case "aggregation":
                    this.modelElement.setIsAssociation(false);
                    this.modelElement.setIsAggregation(true);
                    this.modelElement.setIsComposition(false);
                    break;
                case "composition":
                    this.modelElement.setIsAssociation(false);
                    this.modelElement.setIsAggregation(false);
                    this.modelElement.setIsComposition(true);
                    break;
            }
            break;


        case "srcName":
            this.modelElement.sourceEndInfo.setName(propValue);
            break;
        case "srcVisibility":
            this.modelElement.sourceEndInfo.setVisibility(propValue);
            break;
        case "srcMultiplicity":
            this.modelElement.sourceEndInfo.setMultiplicity(propValue);
            break;
        case "srcIsNavigable":
            this.modelElement.sourceEndInfo.setIsNavigable(propValue === "true");
            break;


        case "trgName":
            this.modelElement.targetEndInfo.setName(propValue);
            break;
        case "trgVisibility":
            this.modelElement.targetEndInfo.setVisibility(propValue);
            break;
        case "trgMultiplicity":
            this.modelElement.targetEndInfo.setMultiplicity(propValue);
            break;
        case "trgIsNavigable":
            this.modelElement.targetEndInfo.setIsNavigable(propValue === "true");
            break;
    }
};
AssociationEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    project.model.removeAndDestroyElement(this.modelElement);
    project.setEditor(this.parentEditor);
};


// ======================== DEPENDENCY EDITOR ========================
// 
DependencyEditor.prototype = new ElementEditor;
function DependencyEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;

    this.htmlSourceEndInput = null;
    this.htmlTargetEndInput = null;
}
DependencyEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("DependencyAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};
DependencyEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_dependency.html", this.htmlEditorDiv, this);
};
DependencyEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("DependencyAttributeName");
    this.htmlSourceEndInput = document.getElementById("DependencyAttributeSource");
    this.htmlTargetEndInput = document.getElementById("DependencyAttributeTarget");

    this.htmlNameInput.value = this.modelElement.name;
    this.htmlSourceEndInput.value = this.modelElement.sourceEnd.name;
    this.htmlTargetEndInput.value = this.modelElement.targetEnd.name;

    this.fillStereotypes();
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
DependencyEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;

    }
};
DependencyEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    project.model.removeAndDestroyElement(this.modelElement);
    project.setEditor(this.parentEditor);
};

// ======================== INHERITANCE EDITOR ========================
// 
InheritanceEditor.prototype = new ElementEditor;
function InheritanceEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlSourceEndInput = null;
    this.htmlTargetEndInput = null;
}
InheritanceEditor.prototype.fillStereotypes = function() {

    this.htmlStereotypeListInput = document.getElementById("InheritanceAttributeStereotypeList");
    loadStereotypeEntries(this.htmlStereotypeListInput, this.modelElement.stereotypes);
};
InheritanceEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_inheritance.html", this.htmlEditorDiv, this);
};
InheritanceEditor.prototype.fillData = function() {

    this.htmlEditorHeader = document.getElementById("InheritanceEditorHeader");

    this.htmlNameInput = document.getElementById("InheritanceAttributeName");
    this.htmlSourceEndInput = document.getElementById("InheritanceAttributeSource");
    this.htmlTargetEndInput = document.getElementById("InheritanceAttributeTarget");

    if (this.modelElement.isGeneralization) {
        this.htmlEditorHeader.innerHTML = "Generalization";
    } else if (this.modelElement.isRealization) {
        this.htmlEditorHeader.innerHTML = "Realization";
    }

    this.htmlNameInput.value = this.modelElement.name;
    this.htmlSourceEndInput.value = this.modelElement.sourceEnd.name;
    this.htmlTargetEndInput.value = this.modelElement.targetEnd.name;

    this.fillStereotypes();
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
InheritanceEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;

    }
};
InheritanceEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    project.model.removeAndDestroyElement(this.modelElement);
    project.setEditor(this.parentEditor);
};

// ======================== STEREOTYPE EDITOR ========================
// 
StereotypeEditor.prototype = new ElementEditor;
function StereotypeEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
}
StereotypeEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_stereotype.html", this.htmlEditorDiv, this);
};
StereotypeEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("StereotypeAttributeName");
    this.htmlNameInput.value = this.modelElement.name;
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
StereotypeEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.modelElement.setName(propValue);
            break;

    }
};
StereotypeEditor.prototype.evDeleteModel = function() {
    
    var c = confirm("This will delete the element PERMANENTLY.\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    if(this.parentEditor) {
        this.parentEditor.modelElement.removeStereotype(this.modelElement);
        this.modelElement.destroy();
        project.setEditor(this.parentEditor);
    }else{
        // TODO ERROR
    }
};

StereotypeEditor.prototype.evNewStereotype = undefined;
StereotypeEditor.prototype.evDeleteStereotype = undefined;
StereotypeEditor.prototype.evSwitchToStereotypeEditor = undefined;


// ======================== DIAGRAM EDITOR ========================
// 
DiagramEditor.prototype = new ElementEditor;
function DiagramEditor(modelElement, parentEditor) {
    this.baseClass = ElementEditor;
    this.baseClass(modelElement, parentEditor);
    // ---
    this.diagram = this.modelElement;
    // --- HTML ELEMENT REFERENCES
    this.htmlNameInput = null;
    this.htmlProjectNameInput = null;
}
DiagramEditor.prototype.fillHtml = function(editorHtmlDiv) {

    this.htmlEditorDiv = editorHtmlDiv;
    // load content to HTML div
    loadHtmlTemplateToElement("templates/template_diagram.html", this.htmlEditorDiv, this);
};
DiagramEditor.prototype.fillData = function() {

    this.htmlNameInput = document.getElementById("DiagramAttributeName");
    this.htmlProjectNameInput = document.getElementById("ProjectAttributeName");
    this.htmlNameInput.value = this.diagram.name;
    this.htmlProjectNameInput.value = project.name;
};
// Event callback to call when a property has been changed through the 
// editor UI elements.
DiagramEditor.prototype.evPropertyChanged = function(propName, propValue) {
    switch (propName) {
        case "name":
            this.diagram.setName(propValue);
            break;
        case "projectName":
            project.setName(propValue);
            break;

    }
};
DiagramEditor.prototype.evDeleteDiagram = function() {
    
    var c = confirm("This will delete the diagram PERMANENTLY.\n"+
                    "(Model elements displayed on it will be retained)\n"+
                    "\n"+
                    "Are you sure you want to continue?");
            
    if(c!==true) return;
    
    project.removeDiagram(this.diagram);
};

DiagramEditor.prototype.evCloseDiagram = function() {
    project.closeDiagram(this.diagram);
};

DiagramEditor.prototype.evNewStereotype = undefined;
DiagramEditor.prototype.evDeleteStereotype = undefined;
DiagramEditor.prototype.evSwitchToStereotypeEditor = undefined;
DiagramEditor.prototype.evDeleteModel = undefined;
DiagramEditor.prototype.evDeleteDiagramElement = undefined;

